package com.thread_pool.thread_pool_executor;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.function.*;

/**
 * 参考博客：https://www.jianshu.com/p/6bac52527ca4
 *
 * 异步编排
 *
 * @author linjy on 2022/11/30
 */
@Slf4j(topic = "c.ThreadPoolExecutorDemo")
@Service
public class ThreadPoolExecutorDemo {


    private ThreadPoolExecutor executor = new ThreadPoolExecutor(
            14,
            21,
            10,
            TimeUnit.MINUTES,
            //如果队列已经是满的，则创建一个新线程，如果线程数量已经达到maxPoolSize，则会执行拒绝策略
            new ArrayBlockingQueue<>(1000),
            new ThreadFactoryBuilder().setNameFormat("trace-thread-%d").build(),//threadFactory 线程工厂，传入Guava创建的ThreadFactoryBuilder
            //该策略下，在调用者线程中直接执行被拒绝任务的run方法，除非线程池已经shutdown，则直接抛弃任务。
            new ThreadPoolExecutor.CallerRunsPolicy());

    @Test
    public void test0() {
        log.info("当前活动线程的数量:{}", executor.getActiveCount());
        log.info("线程池的核心线程数:{}", executor.getCorePoolSize());
        log.info("已提交给线程池的任务总数:{}", executor.getTaskCount());
        log.info("线程池使用的任务队列:{}", executor.getQueue());
    }

    /**
     * 有返回值
     */
    @Test
    public void test1_1() {
        List<CompletableFuture<String>> futuresList = new ArrayList<CompletableFuture<String>>();

        List<String> list = Arrays.asList("hello", "world", "!");

        for (String s : list) {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                return s + "~";
            }, executor);
            futuresList.add(future);
        }

        for (Future<String> future : futuresList) {
            try {
                String result = future.get();
                log.info(result);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    }


    /**
     * 无返回值
     */
    @Test
    public void test1_2() {
        List<CompletableFuture<Void>> futuresList = new ArrayList<CompletableFuture<Void>>();

        List<String> list = Arrays.asList("hello", "world", "!");

        for (String s : list) {
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    log.error(e.getMessage(), e);
                }
                log.info(s + "~");
            }, executor);
            futuresList.add(future);
        }
        CompletableFuture.allOf(futuresList.toArray(new CompletableFuture[]{})).join();

    }

    /**
     * 无返回值
     * ①shutdown() 线程池状态置为shutdown,并不会立即停止：
     * 停止接受外部submit的任务
     * 内部正在执行或者队列中的任务会继续执行，直到结束
     * ②shutdownNow() 线程池状态置为stop，试图立即停止，事实上并不一定
     * 停止接受外部submit的任务
     * 忽略队列中等待的任务
     * 尝试将正在跑的任务interrupt中断
     * 返回未执行的任务列表
     * ③awaitTermination(long timeOut, TimeUnit unit) 阻塞当前线程
     * 等待所有正在执行或队列中的任务执行完
     * 等待时间超时
     * 线程被中断，抛出InterruptedException
     * shutdown请求后所有任务执行完毕，则返回true，超时，则返回false
     * 通常与shutdown联合使用
     * 与shutdown()方法结合使用时，尤其要注意的是shutdown()方法必须要在awaitTermination()方法之前调用，该方法才会生效。否则会造成死锁。
     * 链接：https://www.jianshu.com/p/d0c7bc958173
     * 可以参考若依的线程池关闭
     */
    @Test
    public void test1_2_1() {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            list.add(i + "");
        }

        for (String s : list) {
            CompletableFuture.runAsync(() -> {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    log.error(e.getMessage(), e);
                }
                log.info(s + "~");
            }, executor);
        }
        executor.shutdown();
        try {
            boolean b = executor.awaitTermination(3, TimeUnit.SECONDS);
            System.out.println("b:" + b);
            executor.shutdownNow();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    /**
     * whenComplete、exceptionally方法
     * 计算结果完成时的回调方法
     * 当CompletableFuture的计算结果完成，或者抛出异常的时候，可以执行特定的Action
     */
    @Test
    public void test2() {
        List<CompletableFuture<Void>> futuresList = new ArrayList<CompletableFuture<Void>>();

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
            int i = 12 / 0;

            log.info("run end ...");
        }, executor);
        futuresList.add(future);
        //放在这里不行
        //CompletableFuture.allOf(futuresList.toArray(new CompletableFuture[]{})).join();

        /**
         * whenComplete：是执行当前任务的线程执行继续执行 whenComplete 的任务。
         * whenCompleteAsync：是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。
         */
        future.whenComplete(new BiConsumer<Void, Throwable>() {
            @Override
            public void accept(Void t, Throwable action) {
                log.info("whenComplete执行完成！");
            }
        });

        future.whenCompleteAsync(new BiConsumer<Void, Throwable>() {
            @Override
            public void accept(Void t, Throwable action) {
                log.info("whenCompleteAsync执行完成！");
            }
        }, executor);

        future.exceptionally(new Function<Throwable, Void>() {
            @Override
            public Void apply(Throwable t) {
                log.info("执行失败！{}", t.getMessage());
                return null;
            }
        });
        //future.get();
        CompletableFuture.allOf(futuresList.toArray(new CompletableFuture[]{})).join();

    }


    /**
     * thenApply 方法
     * 当一个线程依赖另一个线程时，可以使用 thenApply 方法来把这两个线程串行化。
     */
    @Test
    public void test3() throws ExecutionException, InterruptedException {
        CompletableFuture<Long> future = CompletableFuture.supplyAsync(new Supplier<Long>() {
            @Override
            public Long get() {
                long result = new Random().nextInt(100);
                log.info("result1=" + result);
                return result;
            }
        }, executor).thenApply(new Function<Long, Long>() {
            @Override
            public Long apply(Long t) {
                long result = t * 5;
                log.info("result2=" + result);
                return result;
            }
        });

        long result = future.get();
        log.info(String.valueOf(result));
    }


    /**
     * handle 是执行任务完成时对结果的处理。
     * handle 方法和 thenApply 方法处理方式基本一样。不同的是 handle 是在任务完成后再执行，还可以处理异常的任务。
     * thenApply 只可以执行正常的任务，任务出现异常则不执行 thenApply 方法。
     */
    @Test
    public void test4() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {

            @Override
            public Integer get() {
                int i = 10 / 0;
                int random = new Random().nextInt(10);
                log.info("random:{}", random);
                return random;
            }
        }, executor).handle(new BiFunction<Integer, Throwable, Integer>() {
            @Override
            public Integer apply(Integer param, Throwable throwable) {
                int result = -1;
                if (throwable == null) {
                    result = param * 2;
                } else {
                    log.error(throwable.getMessage());
                }
                return result;
            }
        });
        log.info(String.valueOf(future.get()));
    }


    /**
     * thenAccept 消费处理结果
     * 接收任务的处理结果，并消费处理，无返回结果
     * 该方法只是消费执行完成的任务，并可以根据上面的任务返回的结果进行处理。并没有后续的输错操作。
     */
    @Test
    public void test5() throws ExecutionException, InterruptedException {
        log.info("start!---");
        String s = "hello world!";
        CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
            try {
                log.info("1");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
            return s + "~~~";
        }, executor);

        /**
         * thenAccept：是执行当前任务的线程执行继续执行 thenAccept 的任务。
         * thenAcceptAsync：是执行把 thenAcceptAsync 这个任务继续提交给线程池来进行执行。
         */
        CompletableFuture<Void> secondFuture2 = firstFuture.thenAccept(str -> {
            log.info("str:{}", str);
            log.info("secondFuture2");
        });

        CompletableFuture<Void> secondFuture1 = firstFuture.thenAcceptAsync(str -> {
            log.info("str:{}", str);
            log.info("secondFuture1");
        }, executor);

        CompletableFuture.allOf(secondFuture1, secondFuture2).join();

        //测试2
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                return new Random().nextInt(10);
            }
        }, executor).thenAcceptAsync(integer -> {
            log.info("随机生成数：{}", String.valueOf(integer));
        }, executor);
        future.get();

    }


    /**
     * thenRun 方法
     * 跟 thenAccept 方法不一样的是，不关心任务的处理结果。只要上面的任务执行完成，就开始执行 thenAccept 。
     */
    @Test
    public void test6() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                return new Random().nextInt(10);
            }
        }, executor).thenRun(() -> {
            log.info("thenRun ...");
        });
        future.get();
    }


    /**
     * thenCombine 合并任务
     * thenCombine 会把 两个 CompletionStage 的任务都执行完成后，把两个任务的结果一块交给 thenCombine 来处理。
     */
    @Test
    public void test7() throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                log.info("hello1");
                return "hello1";
            }
        }, executorService);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                log.info("hello2");
                return "hello2";
            }
        }, executorService);
        CompletableFuture<String> result = future1.thenCombine(future2, new BiFunction<String, String, String>() {
            @Override
            public String apply(String t, String u) {
                log.info(t + " " + u);
                return t + " " + u;
            }
        });
        log.info(result.get());
    }

    /**
     * thenAcceptBoth
     * 当两个CompletionStage都执行完成后，把结果一块交给thenAcceptBoth来进行消耗
     */
    @Test
    public void test8() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int t = new Random().nextInt(3);
                try {
                    TimeUnit.SECONDS.sleep(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("f1=" + t);
                return t;
            }
        }, executor);

        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int t = new Random().nextInt(3);
                try {
                    TimeUnit.SECONDS.sleep(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("f2=" + t);
                return t;
            }
        }, executor);
        CompletableFuture<Void> voidCompletableFuture = f1.thenAcceptBoth(f2, new BiConsumer<Integer, Integer>() {
            @Override
            public void accept(Integer t, Integer u) {
                log.info("f1=" + t + ";f2=" + u + ";");
            }
        });
        log.info(String.valueOf(voidCompletableFuture.get()));
    }


    /**
     * applyToEither 方法
     * 两个CompletionStage，谁执行返回的结果快，我就用那个CompletionStage的结果进行下一步的转化操作。
     */
    @Test
    public void test9() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int t = new Random().nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("f1=" + t);
                return t;
            }
        }, executor);
        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int t = new Random().nextInt(3);
                try {
                    TimeUnit.SECONDS.sleep(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("f2=" + t);
                return t;
            }
        }, executor);

        CompletableFuture<Integer> result = f1.applyToEither(f2, new Function<Integer, Integer>() {
            @Override
            public Integer apply(Integer t) {
                log.info(String.valueOf(t));
                return t * 2;
            }
        });

        log.info(String.valueOf(result.get()));
    }


    /**
     * acceptEither 方法
     * 两个CompletionStage，谁执行返回的结果快，我就用那个CompletionStage的结果进行下一步的消耗操作。
     */
    @Test
    public void test10() {
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int t = new Random().nextInt(3);
                try {
                    TimeUnit.SECONDS.sleep(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("f1=" + t);
                return t;
            }
        });

        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int t = new Random().nextInt(3);
                try {
                    TimeUnit.SECONDS.sleep(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("f2=" + t);
                return t;
            }
        });
        f1.acceptEither(f2, new Consumer<Integer>() {
            @Override
            public void accept(Integer t) {
                log.info(String.valueOf(t));
            }
        });
    }


    /**
     * runAfterEither 方法
     * 两个CompletionStage，任何一个完成了都会执行下一步的操作（Runnable）
     */
    @Test
    public void test11() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int t = new Random().nextInt(3);
                try {
                    TimeUnit.SECONDS.sleep(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("f1=" + t);
                return t;
            }
        }, executor);

        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int t = new Random().nextInt(3);
                try {
                    TimeUnit.SECONDS.sleep(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("f2=" + t);
                return t;
            }
        }, executor);

        CompletableFuture<Void> voidCompletableFuture = f1.runAfterEither(f2, new Runnable() {
            @Override
            public void run() {
                log.info("上面有一个已经完成了。");
            }
        });

        voidCompletableFuture.get();

    }


    /**
     * runAfterBoth
     * 两个CompletionStage，都完成了计算才会执行下一步的操作（Runnable）
     */
    @Test
    public void test12() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int t = new Random().nextInt(3);
                try {
                    TimeUnit.SECONDS.sleep(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("f1=" + t);
                return t;
            }
        }, executor);

        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int t = new Random().nextInt(3);
                try {
                    TimeUnit.SECONDS.sleep(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("f2=" + t);
                return t;
            }
        }, executor);
        CompletableFuture<Void> voidCompletableFuture = f1.runAfterBoth(f2, new Runnable() {

            @Override
            public void run() {
                log.info("上面两个任务都执行完成了。");
            }
        });

        voidCompletableFuture.get();
    }


    /**
     * thenCompose 方法
     * thenCompose 方法允许你对两个 CompletionStage 进行流水线操作，第一个操作完成时，将其结果作为参数传递给第二个操作。
     */
    @Test
    public void test13() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> f = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int t = new Random().nextInt(3);
                log.info("t1=" + t);
                return t;
            }
        }, executor).thenCompose(new Function<Integer, CompletionStage<Integer>>() {
            @Override
            public CompletionStage<Integer> apply(Integer param) {
                return CompletableFuture.supplyAsync(new Supplier<Integer>() {
                    @Override
                    public Integer get() {
                        int t = param * 2;
                        log.info("t2=" + t);
                        return t;
                    }
                });
            }

        });
        log.info("thenCompose result : " + f.get());
    }


}

